/**
 * 
 */
package com.rpframework.utils;


import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

public class RegexUtils {

    public static void main(String[] args) {
        System.out.println("过滤中英文特殊字符: "+RegexUtils.stringFilter("中国~~!#$%%."));
        System.out.println("是否包含中英文特殊字符: "+RegexUtils.isContainsSpecialChar("12"));
        System.out.println("判断中文字符: "+RegexUtils.isChineseChar("中国！"));
        System.out.println("匹配汉字: "+RegexUtils.isChinese("中国！"));
        System.out.println("判断英文字符: "+RegexUtils.isEnglish("abc!"));
        System.out.println("判断合法字符: "+RegexUtils.isRightfulString("abc_-11AAA"));
        System.out.println("邮政编码验证: "+RegexUtils.isZipCode("162406"));
        System.out.println("身份证号码验证: "+RegexUtils.isIdCardNo("35052419880210133e"));
        System.out.println("手机号码验证: "+RegexUtils.isMobile("18918611111"));
        System.out.println("电话号码验证: "+RegexUtils.isPhone("8889333"));
        System.out.println("电话号码验证: "+RegexUtils.htmlFilter("<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题，他可以很随意的设置生成主键的方式。</p>\r\n<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">不管SelectKey有多好，尽量不要遇到这种情况吧，毕竟很麻烦。</p>\r\n<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">&nbsp;</p>\r\n<table border=\"0\" class=\"table table-striped \" style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">\r\n <caption>selectKey Attributes</caption>\r\n <thead>\r\n <tr class=\"a\">\r\n <th>属性</th>\r\n <th>描述</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr class=\"b\">\r\n <td><tt>keyProperty</tt></td>\r\n <td>selectKey 语句结果应该被设置的目标属性。</td>\r\n </tr>\r\n <tr class=\"a\">\r\n <td><tt>resultType</tt></td>\r\n <td>结果的类型。MyBatis 通常可以算出来,但是写上也没有问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。</td>\r\n </tr>\r\n <tr class=\"b\">\r\n <td><tt>order</tt></td>\r\n <td>这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用。</td>\r\n </tr>\r\n <tr class=\"a\">\r\n <td><tt>statementType</tt></td>\r\n <td>和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 语句的映射类型,分别代表 PreparedStatement 和CallableStatement 类型。</td>\r\n </tr>\r\n </tbody>\r\n</table>\r\n<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">&nbsp;</p>\r\n<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">SelectKey需要注意order属性，像Mysql一类支持自动增长类型的数据库中，order需要设置为after才会取到正确的值。</p>\r\n<p style=\"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;\">像Oracle这样取序列的情况，需要设置为before，否则会报错。</p>"));
        System.out.println("匹配密码: "+RegexUtils.isPwd("d888d_ddddd"));
        System.out.println("匹配密码: "+RegexUtils.isUrl("http://baidu.com"));
        System.out.println("验证字符: "+RegexUtils.stringCheck("中文aabc001_-"));
        System.out.println(isEmail("416501600@qq.com"));
    }
    
    /**
     * 匹配URL地址
     * @param str
     * @return
     */
    public final static boolean isUrl(String str) {
        return match(str, "^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$");
    }
    
    /**
     * 匹配密码，以字母开头，长度在6-18之间，只能包含字符、数字和下划线。
     * @param str
     * @return
     */
    public final static boolean isPwd(String str) {
        return match(str, "^[a-zA-Z]\\w{6,18}$");
    }
    
    /**
     * 验证字符，只能包含中文、英文、数字、下划线等字符。
     * @param str
     * @return
     */
    public final static boolean stringCheck(String str) {
        return match(str, "^[a-zA-Z0-9\u4e00-\u9fa5-_]+$");
    }
    
    /**
     * 匹配Email地址
     * @param str
     * @return
     */
    public final static boolean isEmail(String str) {
        return match(str, "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
    }

    /**
     * 联系电话(手机/电话皆可)验证   
     * @param text
     * @return
     */
    public final static boolean isTel(String text){
        if(isMobile(text)||isPhone(text)) return true;
        return false;
    }
    
    /**
     * 只能输入数字
     * @param text
     * @return
     */
    public final static boolean isPhone(String text){
        return match(text, "^(\\d{3,4}-?)?\\d{7,9}$");
    }
    
    /**
     * 手机号码验证
     * @param text
     * @return
     */
    public final static boolean isMobile(String text){
        if(text.length()!=11) return false;
        return match(text, "^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\\d{8})$");
    }
    
    /**
     * 身份证号码验证 
     * @param text
     * @return
     */
    public final static boolean isIdCardNo(String text){
        return match(text, "^(\\d{6})()?(\\d{4})(\\d{2})(\\d{2})(\\d{3})(\\w)$");
    }
    
    /**
     * 邮政编码验证 
     * @param text
     * @return
     */
    public final static boolean isZipCode(String text){
        return match(text, "^[0-9]{6}$");
    }
 
    /**
     * 判断是否为合法字符(a-zA-Z0-9-_)
     * @param text
     * @return
     */
    public final static boolean isRightfulString(String text){
        return match(text, "^[A-Za-z0-9_-]+$"); 
    }
    
    /**
     * 判断英文字符(a-zA-Z)
     * @param text
     * @return
     */
    public final static boolean isEnglish(String text){
        return match(text, "^[A-Za-z]+$"); 
    }
    
    /**
     * 判断中文字符(包括汉字和符号)
     * @param text
     * @return
     */
    public final static boolean isChineseChar(String text){
        return match(text, "^[\u0391-\uFFE5]+$");
    }
    
    /**
     * 匹配汉字
     * @param text
     * @return
     */
    public final static boolean isChinese(String text){
        return match(text, "^[\u4e00-\u9fa5]+$");
    }
    
    /**
     * 是否包含中英文特殊字符，除英文"-_"字符外
     * @param text
     * @return
     */
    public static boolean isContainsSpecialChar(String text) {
        if(StringUtils.isBlank(text)) return false;
        String[] chars={"[","`","~","!","@","#","$","%","^","&","*","(",")","+","=","|","{","}","'",
                ":",";","'",",","[","]",".","<",">","/","?","~","！","@","#","￥","%","…","&","*","（","）",
                "—","+","|","{","}","【","】","‘","；","：","”","“","’","。","，","、","？","]"};
        for(String ch : chars){
            if(text.contains(ch)) return true;
        }
        return false;
    }
    
    /**
     * 过滤中英文特殊字符，除英文"-_"字符外
     * @param text
     * @return
     */
    public static String stringFilter(String text) {
        String regExpr="[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";  
        Pattern p = Pattern.compile(regExpr);
        Matcher m = p.matcher(text);
        return m.replaceAll("").trim();     
    }
    
    /**
     * 过滤html代码
     * @param inputString
     * @return
     */
    public static String htmlFilter(String inputString) {
        String htmlStr = inputString; // 含html标签的字符串
        String textStr = "";
        java.util.regex.Pattern p_script;
        java.util.regex.Matcher m_script;
        java.util.regex.Pattern p_style;
        java.util.regex.Matcher m_style;
        java.util.regex.Pattern p_html;
        java.util.regex.Matcher m_html;
        java.util.regex.Pattern p_ba;
        java.util.regex.Matcher m_ba;

        try {
            String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; // 定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
            // }
            String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; // 定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
            // }
            String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
            String patternStr = "\\s+";

            p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
            m_script = p_script.matcher(htmlStr);
            htmlStr = m_script.replaceAll(""); // 过滤script标签

            p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
            m_style = p_style.matcher(htmlStr);
            htmlStr = m_style.replaceAll(""); // 过滤style标签

            p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
            m_html = p_html.matcher(htmlStr);
            htmlStr = m_html.replaceAll(""); // 过滤html标签

            p_ba = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
            m_ba = p_ba.matcher(htmlStr);
            htmlStr = m_ba.replaceAll(""); // 过滤空格

            textStr = htmlStr;

        } catch (Exception e) {
            System.err.println("Html2Text: " + e.getMessage());
        }
        return textStr;// 返回文本字符串
    }
    
    /**
     * 正则表达式匹配
     * @param text
     * @param reg
     * @return
     */
    private final static boolean match(String text, String reg) {
        if (StringUtils.isBlank(text) || StringUtils.isBlank(reg))
            return false;
        return Pattern.compile(reg).matcher(text).matches();
    }
    
    

// 参考地址：http://www.cnblogs.com/yansheng/archive/2010/05/07/1730188.html    

// 附 ： 常用的正则表达式：
//    匹配特定数字：
//    ^[1-9]d*$　 　 //匹配正整数
//    ^-[1-9]d*$ 　 //匹配负整数
//    ^-?[1-9]d*$　　 //匹配整数
//    ^[1-9]d*|0$　 //匹配非负整数（正整数 + 0）
//    ^-[1-9]d*|0$　　 //匹配非正整数（负整数 + 0）
//    ^[1-9]d*.d*|0.d*[1-9]d*$　　 //匹配正浮点数
//    ^-([1-9]d*.d*|0.d*[1-9]d*)$　 //匹配负浮点数
//    ^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$　 //匹配浮点数
//    ^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$　　 //匹配非负浮点数（正浮点数 + 0）
//    ^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$　　//匹配非正浮点数（负浮点数 + 0）
//    评注：处理大量数据时有用，具体应用时注意修正
//
//    匹配特定字符串：
//    ^[A-Za-z]+$　　//匹配由26个英文字母组成的字符串
//    ^[A-Z]+$　　//匹配由26个英文字母的大写组成的字符串
//    ^[a-z]+$　　//匹配由26个英文字母的小写组成的字符串
//    ^[A-Za-z0-9]+$　　//匹配由数字和26个英文字母组成的字符串
//    ^w+$　　//匹配由数字、26个英文字母或者下划线组成的字符串
//
//    在使用RegularExpressionValidator验证控件时的验证功能及其验证表达式介绍如下:
//
//    只能输入数字：“^[0-9]*$”
//    只能输入n位的数字：“^d{n}$”
//    只能输入至少n位数字：“^d{n,}$”
//    只能输入m-n位的数字：“^d{m,n}$”
//    只能输入零和非零开头的数字：“^(0|[1-9][0-9]*)$”
//    只能输入有两位小数的正实数：“^[0-9]+(.[0-9]{2})?$”
//    只能输入有1-3位小数的正实数：“^[0-9]+(.[0-9]{1,3})?$”
//    只能输入非零的正整数：“^+?[1-9][0-9]*$”
//    只能输入非零的负整数：“^-[1-9][0-9]*$”
//    只能输入长度为3的字符：“^.{3}$”
//    只能输入由26个英文字母组成的字符串：“^[A-Za-z]+$”
//    只能输入由26个大写英文字母组成的字符串：“^[A-Z]+$”
//    只能输入由26个小写英文字母组成的字符串：“^[a-z]+$”
//    只能输入由数字和26个英文字母组成的字符串：“^[A-Za-z0-9]+$”
//    只能输入由数字、26个英文字母或者下划线组成的字符串：“^w+$”
//    验证用户密码:“^[a-zA-Z]\\w{5,17}$”正确格式为：以字母开头，长度在6-18之间，
//
//    只能包含字符、数字和下划线。
//    验证是否含有^%&’,;=?$”等字符：“[^%&’,;=?$x22]+”
//    只能输入汉字：“^[u4e00-u9fa5],{0,}$”
//    验证Email地址：“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”
//    验证InternetURL：“^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$”
//    验证电话号码：“^((d{3,4})|d{3,4}-)?d{7,8}$”
//
//    正确格式为：“XXXX-XXXXXXX”，“XXXX-XXXXXXXX”，“XXX-XXXXXXX”，
//
//    “XXX-XXXXXXXX”，“XXXXXXX”，“XXXXXXXX”。
//    验证身份证号（15位或18位数字）：“^d{15}|d{}18$”
//    验证一年的12个月：“^(0?[1-9]|1[0-2])$”正确格式为：“01”-“09”和“1”“12”
//    验证一个月的31天：“^((0?[1-9])|((1|2)[0-9])|30|31)$” 正确格式为：“01”“09”和“1”“31”。
//
//    匹配中文字符的正则表达式： [u4e00-u9fa5]
//    匹配双字节字符(包括汉字在内)：[^x00-xff]
//    匹配空行的正则表达式：n[s| ]*r
//    匹配HTML标记的正则表达式：/< (.*)>.*|< (.*) />/
//    匹配首尾空格的正则表达式：(^s*)|(s*$)
//    匹配Email地址的正则表达式：w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
//    匹配网址URL的正则表达式：^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$
}
